package com.cctc.rds.scheduler.server.raft.apply;

import com.cctc.rds.nrpc.core.util.JsonUtils;
import com.cctc.rds.raft.core.log.Log;
import com.cctc.rds.raft.core.log.commit.statemachine.StateMachine;
import com.cctc.rds.scheduler.core.task.TaskLog;
import com.cctc.rds.scheduler.server.raft.Command;
import com.cctc.rds.scheduler.server.storage.Storage;

import java.nio.charset.StandardCharsets;

/**
 * LevelDB 内存数据库 - 本机任务日志操作命令应用状态机。
 */
public class TaskLogStateMachine implements StateMachine {
    private final Storage storage;
    private final CommandHandler[] commandHandlers;

    public TaskLogStateMachine(Storage storage) {
        this.storage = storage;
        this.commandHandlers = new CommandHandler[]{
                new SaveCommandHandler(),
                new RemoveCommandHandler()
        };
    }

    @Override
    public boolean apply(Log commitLog) {
        String command = new String(commitLog.getCommand(), StandardCharsets.UTF_8);
        for (CommandHandler commandHandler : commandHandlers) {
            if (commandHandler.match(command)) {
                commandHandler.exec(command);
            }
        }
        return true;
    }


    public interface CommandHandler {
        boolean match(String command);

        void exec(String command);
    }

    public class SaveCommandHandler implements CommandHandler {

        @Override
        public boolean match(String command) {
            return command.startsWith(Command.SAVE.substring(0, 4));
        }

        @Override
        public void exec(String command) {
            String[] taskInfo = split(command.substring(4), ",", 3);
            String app = taskInfo[0];
            long taskId = Long.parseLong(taskInfo[1]);
            TaskLog taskLog = JsonUtils.fromJson(taskInfo[2], TaskLog.class);
            storage.save(app, taskId, taskLog);
        }
    }

    public class RemoveCommandHandler implements CommandHandler {

        @Override
        public boolean match(String command) {
            return command.startsWith(Command.SAVE.substring(0, 6));
        }

        @Override
        public void exec(String command) {
            String[] taskInfo = split(command.substring(6), ",", 2);
            String app = taskInfo[0];
            long taskId = Long.parseLong(taskInfo[1]);
            storage.remove(app, taskId);
        }
    }

    private String[] split(String source, String regex, int count) {
        String[] ans = new String[count];
        for (int i = 0; i < count; i++) {
            int index = source.indexOf(regex);
            if (index == -1 || index == count - 1) {
                ans[i] = source.trim();
            }
            ans[i] = source.substring(0, index).trim();
            source = source.substring(index + 1);
        }
        return ans;
    }

}
